package core

import (
	"fmt"
	"net"
	"os"
	"sort"
	"strconv"
	"strings"
)

const InternalCmdPrefix = "--"
const (
	InternalCmdHelp = "help"
	InternalCmdTui  = "tui" // 新增TUI命令
)

type Cmd struct {
	Device     string
	plugHandle *Plug
}

func NewCmd(p *Plug) *Cmd {
	return &Cmd{
		plugHandle: p,
	}
}

// start
func (cm *Cmd) Run() {
	// print help
	if len(os.Args) <= 1 {
		cm.printHelpMessage()
		os.Exit(1)
	}

	// parse command
	firstArg := string(os.Args[1])
	if strings.HasPrefix(firstArg, InternalCmdPrefix) {
		cmd := strings.Trim(firstArg, InternalCmdPrefix)
		if cmd == InternalCmdTui { // 参数为--tui
			cm.startTUI() // 该位置会间接启用 cm.plugHandle.SetOption, 回到core->Run堆栈后会运行Capture
		} else { // 参数非--tui, 但是以--开头
			cm.printHelpMessage()
			os.Exit(1)
		}
	} else { // 参数非--开头, 以cmd设置参数开头
		cm.parsePlugCmd() // 该位置同样会间接启用 cm.plugHandle.SetOption, 回到core->Run堆栈后会运行Capture
	}
}

// usage
func (cm *Cmd) printHelpMessage() {
	cm.printPlugList()
	fmt.Println("==================================================================================")
	fmt.Println("[Usage]")
	fmt.Println("🐛 Go-Sniffer Configuration:")
	fmt.Println("    go-sniffer [device] [plug] [plug's params(optional)]")
	fmt.Println()
	fmt.Println("    [exp]")
	fmt.Println("          go-sniffer en0 redis          Capture redis packet")
	fmt.Println("          go-sniffer en0 mysql -p 3306  Capture mysql packet")
	fmt.Println()
	fmt.Println("    go-sniffer --[commend]")
	fmt.Println("               --help \"this page\"")
	fmt.Println("               --tui  \"start TUI interface\"") // 新增TUI说明
	fmt.Println("==================================================================================")
	fmt.Println("# Go-Sniffer device list:")
	cm.printDevice()
	fmt.Println("==================================================================================")
	fmt.Println("# Go-Sniffer master version:")
	fmt.Println(cxt.Version)
}

// print plug-in list
func (cm *Cmd) printPlugList() {
	// 获取内置插件数量
	l := len(cm.plugHandle.InternalPlugList)
	fmt.Println("# Number of internal-protocol-plug : " + strconv.Itoa(l))

	// 收集插件名称（按字母排序）
	if l > 0 {
		// 提取插件名称并排序
		var plugNamesNames []string
		for plugNames := range cm.plugHandle.InternalPlugList {
			plugNamesNames = append(plugNamesNames, plugNames)
		}
		sort.Strings(plugNamesNames)

		// 格式化输出（带序号和图标）
		for i, name := range plugNamesNames {
			fmt.Printf("  %d. %s\n", i+1, name)
		}
	} else {
		fmt.Println("# No internal protocol-plug found")
	}
}

// print device
func (cm *Cmd) printDevice() {
	ifaces, err := net.Interfaces()
	if err != nil {
		panic(err)
	}
	for _, iface := range ifaces {
		addrs, _ := iface.Addrs()
		for _, a := range addrs {
			if ipnet, ok := a.(*net.IPNet); ok {
				if ip4 := ipnet.IP.To4(); ip4 != nil {
					fmt.Println("[device] : " + iface.Name + " : " + iface.HardwareAddr.String() + "  " + ip4.String())
				}
			}
		}
	}
}

// Parameters needed for plug-ins
func (cm *Cmd) parsePlugCmd() {
	if len(os.Args) < 3 {
		cm.printHelpMessage()
		os.Exit(1)
	}

	cm.Device = os.Args[1]
	plugName := os.Args[2]
	plugParams := os.Args[3:]

	fmt.Println("# Starting CMD interface...")

	// 输出模式内配置选择项
	fmt.Printf("▶️Selected: Interface=%s, Plugin=%s, Params=%s\n", cm.Device, plugName, plugParams)

	cm.plugHandle.SetOption(plugName, plugParams)
}

// 新增TUI启动方法
func (cm *Cmd) startTUI() {
	fmt.Println("# Starting TUI interface...")

	// 获取网络接口信息
	interfaces := cm.getNetworkInterfacesWithDetails()

	// 获取插件列表(只支持内置的, 扩展插件不做了)
	var internalPlugsName []string
	for inPlugName := range cm.plugHandle.InternalPlugList {
		internalPlugsName = append(internalPlugsName, inPlugName)
	}

	// 首字母排序后复制[]plugins
	sort.Strings(internalPlugsName)
	plugins := internalPlugsName

	// 启动TUI选择界面
	selectedInterface, selectedPlugin, port := runTUI(interfaces, plugins)

	if selectedInterface == "" || selectedPlugin == "" {
		fmt.Println("❌ 选择已取消！未完成网络接口或插件的选择。")
		fmt.Println("❌ 请重新运行程序并完成以下步骤：")
		fmt.Println("   1. 使用上下方向键选择网络接口")
		fmt.Println("   2. 按Tab键切换到插件列表, 选择需要的协议插件")
		fmt.Println("   3. 按Tab键切换到端口输入框, 可修改默认端口")
		fmt.Println("   4. 按Tab键切换到「🚀 Start Sniffing」按钮, 按Enter开始抓包")
		fmt.Println("❌ 提示：若需查看帮助，可运行命令 `go-sniffer --help`")
		os.Exit(1)
	}

	// 设置选择结果
	cm.Device = selectedInterface

	// 输出模式内配置选择项
	fmt.Printf("▶️Selected: Interface=%s, Plugin=%s, Port=%d\n", selectedInterface, selectedPlugin, port)

	// Run
	cm.plugHandle.SetOption(selectedPlugin, []string{"-p", strconv.Itoa(port)})
}

// 新增方法：获取带详细信息的网络接口
func (cm *Cmd) getNetworkInterfacesWithDetails() []map[string]string {
	var interfaces []map[string]string

	ifaces, err := net.Interfaces()
	if err != nil {
		return interfaces
	}

	for _, iface := range ifaces {
		addrs, _ := iface.Addrs()
		for _, a := range addrs {
			if ipnet, ok := a.(*net.IPNet); ok {
				if ip4 := ipnet.IP.To4(); ip4 != nil {
					interfaceInfo := map[string]string{
						"name": iface.Name,
						"mac":  iface.HardwareAddr.String(),
						"ip":   ip4.String(),
					}
					interfaces = append(interfaces, interfaceInfo)
				}
			}
		}
	}
	return interfaces
}
